#include <atomic>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#define private public
#include "async_logger.h"
#undef private
#include "gtest/gtest.h"

namespace Base {
namespace SystemLog {
using namespace std::chrono_literals;
namespace {
constexpr size_t TEST_BUFFER_SIZE = 1024 * 1024; // 1MB
constexpr size_t TEST_MESSAGE_SIZE = 128;
constexpr int TEST_MESSAGES_COUNT = 1000;
constexpr int32_t TEST_THREADS = 16;
const char TEST_CHAR = 'T';
const double TEST_MB = 1024.0 * 1024.0;

class TestOutput {
public:
    ErrCode Append(const char* data, size_t len) {
        (void)data; // 标记未使用参数
        totalBytes_ += len;
        return ERR_OK;
    }
    
    size_t GetTotalBytes() const { return totalBytes_; }
    
private:
    size_t totalBytes_ = 0;
};

class PerfTimer {
public:
    PerfTimer() : start_(std::chrono::high_resolution_clock::now()) {}
    
    double elapsed() const {
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double>(end - start_).count();
    }
    
private:
    std::chrono::time_point<std::chrono::high_resolution_clock> start_;
};

} // namespace

class AsyncLoggerPerformanceTest : public testing::Test {
public:
    static void SetUpTestCase(void) {}
    static void TearDownTestCase(void) {}
    void SetUp() override {
        testOutput_ = std::make_shared<TestOutput>();
        auto task = [this](const char* data, size_t len) -> ErrCode {
            return testOutput_->Append(data, len);
        };
        logger_ = std::make_unique<AsyncLogger<TEST_BUFFER_SIZE>>(task);
    }
    
    void TearDown() override {
        if (logger_ && logger_->running_.load()) {
            logger_->Stop();
        }
        logger_.reset();
        testOutput_.reset();
    }

protected:
    std::unique_ptr<AsyncLogger<TEST_BUFFER_SIZE>> logger_;
    std::shared_ptr<TestOutput> testOutput_;
};

/**
 * @tc.name: AsyncLoggerPerformanceTest_001
 * @tc.desc: verify multi-threaded logging performance
 * @tc.type: PERF
 */
TEST_F(AsyncLoggerPerformanceTest, AsyncLoggerPerformanceTest_001)
{
    std::vector<std::thread> threads;
    std::atomic<int> readyCount{0};
    std::atomic<bool> start{false};
    std::atomic<size_t> successCount{0};
    std::atomic<size_t> failCount{0};
    const std::string message(TEST_MESSAGE_SIZE, TEST_CHAR);
    const int32_t totalMessages = TEST_THREADS * TEST_MESSAGES_COUNT;
    const size_t expectedBytes = totalMessages * TEST_MESSAGE_SIZE;

    auto worker = [&]() {
        readyCount++;
        while (!start) {
            std::this_thread::yield();
        }
        for (int i = 0; i < TEST_MESSAGES_COUNT; ++i) {
            auto errCode = logger_->Append(message.c_str(), message.size());
            if (errCode == ERR_OK) {
                successCount.fetch_add(1, std::memory_order_relaxed);
            } else {
                failCount.fetch_add(1, std::memory_order_relaxed);
            }
            std::this_thread::sleep_for(10us);
        }
    };
    
    logger_->Start();
    
    for (int i = 0; i < TEST_THREADS; i++) {
        threads.emplace_back(worker);
    }
    while (readyCount < TEST_THREADS) {
        std::this_thread::sleep_for(1ms);
    }

    PerfTimer timer;
    start = true;
    for (auto &t : threads) {
        t.join();
    }

    // 确保所有异步操作完成
    EXPECT_EQ(logger_->Flush(), ERR_OK);
    double elapsed = timer.elapsed();
    GTEST_LOG_(INFO) << "[PERFORMANCE REPORT]\n";
    GTEST_LOG_(INFO) << "Success: " << successCount << " | Failed: " << failCount << "\n";
    GTEST_LOG_(INFO) << "Threads: " << TEST_THREADS << "\n";
    GTEST_LOG_(INFO) << "Messages per thread: " << TEST_MESSAGES_COUNT << "\n";
    GTEST_LOG_(INFO) << "Total messages: " << totalMessages << "\n";
    GTEST_LOG_(INFO) << "Message size: " << TEST_MESSAGE_SIZE << " bytes\n";
    GTEST_LOG_(INFO) << "Elapsed time: " << elapsed << " seconds\n";
    GTEST_LOG_(INFO) << "Throughput: " << totalMessages / elapsed << " msg/sec\n";
    GTEST_LOG_(INFO) << "Bandwidth: " << expectedBytes / TEST_MB / elapsed << " MB/sec\n";
    GTEST_LOG_(INFO) << "TotalBytes: " << testOutput_->GetTotalBytes() << " | " <<
        "expectedBytes: "<< expectedBytes << "\n";
    
    // 确保所有消息都成功
    EXPECT_EQ(successCount.load(), static_cast<size_t>(totalMessages));
    EXPECT_EQ(failCount.load(), static_cast<size_t>(0));
    EXPECT_EQ(testOutput_->GetTotalBytes(), expectedBytes);
}

} // namespace SystemLog
} // namespace Base
